package Controller;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.util.StringTokenizer;
import java.util.Vector;

import persistencia.AdministradorPersistenciaCliente;
import persistencia.AdministradorPersistenciaConsumos;
import persistencia.AdministradorPersistenciaLinea;
import persistencia.AdministradorPersistenciaPlan;
import persistencia.AdministradorPersistenciaServicio;
import Model.Cliente;
import Model.ClienteView;
import Model.Consumo;
import Model.Estado;
import Model.Factura;
import Model.ItemFactura;
import Model.Linea;
import Model.LineaAdicional;
import Model.LineaDisponible;
import Model.LineaDisponibleView;
import Model.LineaView;
import Model.Paquete;
import Model.Plan;
import Model.PlanView;
import Model.RegistroConsumo;
import Model.Servicio;
import Model.ServicioView;
import Model.RegistroConsumoView;

public class Sistema {
	
	private Vector <Cliente> clientes;
	private static Sistema instancia;
	private Vector <LineaDisponible> lineasDisponibles;
	private Vector <Estado> estados;
	private Vector <Plan> planes;
	private Vector <Servicio> servicios;
	private Vector <Factura> facturas;
	
		
	
	public static Sistema getInstancia(){
		if (instancia == null){
			instancia = new Sistema ();
			instancia.cargarDatos();
		}
		return instancia;
	}
	
	private void cargarDatos() {
		cargarServicios();
		cargarPlanes();
		cargarClientes();
		cargarLineasDisponibles();
		
	}

	public Estado getEstado (int codigo){
		return estados.get(codigo-1);
	}
	
	public Vector<LineaDisponibleView> getLineasDisponibles (){
		Vector<LineaDisponibleView> auxLineasDisponibles = new Vector<LineaDisponibleView>();
		LineaDisponibleView auxLineaDisponible;
		for(LineaDisponible lineaDisponible : lineasDisponibles){
			auxLineaDisponible = new LineaDisponibleView(lineaDisponible.getNumero());
			Estado estado = lineaDisponible.getEstado();
			if(estado.getCodigo() == 1){
				auxLineasDisponibles.add(auxLineaDisponible);
			}
		}
		return auxLineasDisponibles;
	}
	
	private Sistema (){
		clientes = new Vector<Cliente>();
		lineasDisponibles = new Vector<LineaDisponible>();
		estados = new Vector <Estado>();
		servicios = new Vector<Servicio>();
		planes = new Vector<Plan>();
		facturas = new Vector<Factura>();
		estados.add(new Estado(1, "Disponible"));
		estados.add(new Estado(2, "No Disponible"));
		
	}
	
	private void cargarLineasDisponibles(){
		lineasDisponibles = AdministradorPersistenciaLinea.getInstancia().buscarLineasDisponibles();
	}
	
	private void cargarClientes() {
		clientes = AdministradorPersistenciaCliente.getInstancia().buscarTodos();
	}

	private void cargarPlanes() {
		planes = AdministradorPersistenciaPlan.getInstancia().buscarTodos();
		
	}

	private void cargarServicios() {
		servicios = AdministradorPersistenciaServicio.getInstancia().buscarTodos();
	}

	public Vector<ClienteView> buscarCliente(String dni, String nombre, String apellido) {
		Vector <ClienteView> resultado = new Vector<ClienteView>();
		if (dni.isEmpty() && nombre.isEmpty() && apellido.isEmpty()){
			for (Cliente cliente : clientes){
				resultado.add(cliente.getView());
			}
		}else{
			for (Cliente cliente : clientes){
				if(cliente.getDni().equals(dni)){
					resultado.add(cliente.getView());
				}
				else if (cliente.getNombre() == nombre && cliente.getApellido() == apellido){
					resultado.add(cliente.getView());
				}
				else if (cliente.getApellido() == apellido){
					resultado.add(cliente.getView());
				}
				else if (cliente.getNombre() == nombre){
					resultado.add(cliente.getView());
				}
			}
		}
		return resultado;
	}

	public void altaCliente(String nombre, String apellido, String dni,String direccion,String telefono, String email, String numero, int nroPlan){
		Cliente clienteNuevo = new Cliente(nombre, apellido,dni, direccion, telefono, email);
		Linea lineaNueva = new Linea(numero);
		lineaNueva.setPlan(buscarPlan(nroPlan));
		clienteNuevo.agregarLinea(lineaNueva);
		clientes.add(clienteNuevo);
		LineaDisponible lineaDisponible = buscarLineaDisponible(numero);
		lineaDisponible.setEstado(getEstado(Estado.NO_DISPONIBLE));
		AdministradorPersistenciaCliente.getInstancia().insert(clienteNuevo);
		AdministradorPersistenciaLinea.getInstancia().insert(lineaNueva, dni);
	}
	

	private LineaDisponible buscarLineaDisponible(String numero) {
		LineaDisponible lineaDisponibleEncontrada = null;
		for(LineaDisponible lineaDisponible : lineasDisponibles){
			if(lineaDisponible.getNumero().equalsIgnoreCase(numero)){
				lineaDisponibleEncontrada = lineaDisponible;
			}
		}
		return lineaDisponibleEncontrada;
	}
	
	public Plan buscarPlan (int nroPlanABuscar){
		
		for(Plan plan : planes){
			if (plan.getNroPlan() == nroPlanABuscar)
				return plan;
		}
		
		return AdministradorPersistenciaPlan.getInstancia().buscarPlan(nroPlanABuscar);
	}
	
	public int indexOfPlan (int nroPlanABuscar){
		int i=0;
		while (planes.get(i).getNroPlan()!= nroPlanABuscar){
			i++;
		}
		if (planes.get(i).getNroPlan()== nroPlanABuscar){
			return i;
		}
		return -1;
	}

	public void altaLineaAdicional (String dni, String numeroAdicional, String nombreAdicional,int nroPlan){
		LineaAdicional adicional = new LineaAdicional(numeroAdicional,nombreAdicional);
		adicional.setPlan(buscarPlan(nroPlan));
		Cliente cliente = buscarCliente(dni);
		cliente.agregarLinea(adicional);
		LineaDisponible lineaDisponible = buscarLineaDisponible(numeroAdicional);
		lineaDisponible.setEstado(getEstado(Estado.NO_DISPONIBLE));
		AdministradorPersistenciaLinea.getInstancia().insert(adicional, dni);
	}
	
	
	public void setPlan (String dni, String numero, int nroPlanNuevo){
		Cliente cliente = buscarCliente(dni);
		cliente.getLinea(numero).setPlan(planes.get(indexOfPlan(nroPlanNuevo)));
	}

	public boolean modificarCliente(String dniABuscar, String nombre, String apellido,
			String dni, String direccion, String telefono) {
		Cliente clienteModificado = buscarCliente(dniABuscar);
		clienteModificado.setNombre(nombre);
		clienteModificado.setApellido(apellido);
		clienteModificado.setDni(dni);
		clienteModificado.setDireccion(direccion);
		clienteModificado.setTelefono(telefono);
		
		AdministradorPersistenciaCliente.getInstancia().update(clienteModificado);
		return true;
	}
	
	public void modificarPlan (int nroPlan, String descripcion, int smsDisponibles, int minutosLibres, float precioSmsAdicional, float precioMinutoAdicional){
		Plan planAModificar = planes.get(indexOfPlan(nroPlan));
		planAModificar.setDescripcion(descripcion);
		
	}
	
	public void modificarPlanBase (int nroPlan, String descripcion, int smsDisponibles, int minutosLibres, float precioSmsAdicional, float precioMinutoAdicional, int cantidadDatos, float costoDatosAdicional){
		Plan planAModificar = planes.get(indexOfPlan(nroPlan));
		planAModificar.setCostoAdicionalMinutosLibres(precioMinutoAdicional);
		planAModificar.setCostoAdicionalSMS(precioSmsAdicional);
		planAModificar.setCantidadMinutosLibres(minutosLibres);
		planAModificar.setCantidadSMS(smsDisponibles);
		planAModificar.setDescripcion(descripcion);
		planAModificar.setCantidadDatos(cantidadDatos);
		planAModificar.setCostoAdicionalDatos(costoDatosAdicional);
		
		
	}

	private Cliente buscarCliente(String dniABuscar) {
		Cliente clienteEncontrado = null;
		for(Cliente cliente : clientes){
			if(cliente.getDni().equalsIgnoreCase(dniABuscar)){
				clienteEncontrado = cliente;
			}
		}
		return clienteEncontrado;
	}
	
	public Vector<LineaView> listarLineasCliente (String dni){
		return buscarCliente(dni).getView().getLineas();
	}

	public Vector<PlanView> getPlanesDisponibles() {		
		Vector<PlanView> planesView = new Vector<PlanView>();
		int i=0;
		while (i< planes.size()){
			planesView.add(planes.get(i).getView());
			i++;
		}		
		return planesView;
	}

	public void desvincularLinea (String dni, String lineaADesvincular){
		Cliente cliente = buscarCliente(dni);
		cliente.eliminarLinea(lineaADesvincular);
		LineaDisponible lineaALiberar = buscarLineaDisponible(lineaADesvincular);
		lineaALiberar.setEstado(getEstado(Estado.DISPONIBLE));
		AdministradorPersistenciaLinea.getInstancia().delete(lineaADesvincular);
	}

	public void registrarConsumos() {
		URL url = getClass().getResource("../consumos.txt");
		File file = new File(url.getPath());
		try {
			String nroDni = null;
			int cantConsumo = 0;
			String descripcion = null;
			String nroLinea = null;
			Cliente cliente;
			Linea linea;
			Servicio servicio;
			Consumo consumo;
			BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
			String line = null;
			Vector<Consumo> consumos = new Vector<Consumo>();
			while((line = bufferedReader.readLine()) != null){
				StringTokenizer st = new StringTokenizer(line, ",");
				nroDni = st.nextToken();
				cantConsumo = Integer.parseInt(st.nextToken());
				nroLinea = st.nextToken();
				descripcion = st.nextToken();
				
				cliente = buscarCliente(nroDni);
				linea = cliente.getLinea(nroLinea);
				servicio = linea.getPlan().getServicio(descripcion);
				consumo = new Consumo(cantConsumo, nroLinea,nroDni, servicio);
				cliente.registrarConsumo(consumo);
				consumos.add(consumo);
				
			}
			bufferedReader.close();
			AdministradorPersistenciaConsumos.getInstancia().registrarConsumos(consumos);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public void cambiarNombreLineaAdicional (String dniTitular, String nroLinea, String nombreNuevo){
		Cliente clienteAModificar = buscarCliente(dniTitular);
		Vector <Linea> lineasCliente = clienteAModificar.getLineas();
		int i=0;
		while(!lineasCliente.elementAt(i).getNroLinea().equals(nroLinea)){
			i++;
		}
		if (lineasCliente.elementAt(i).getNroLinea().equals(nroLinea)){
			((LineaAdicional)lineasCliente.elementAt(i)).setNombreAdicional(nombreNuevo);
			AdministradorPersistenciaLinea.getInstancia().update(lineasCliente.elementAt(i));
		}
	}

	public RegistroConsumoView obtenerRegistroConsumo(String dni, String nroLinea) {
		Cliente cliente = buscarCliente(dni);
		return cliente.getRegistroConsumo().getView(nroLinea);
	}

	public void generarFacturacion() {	
		for(Cliente cliente : clientes){
			RegistroConsumo registroConsumo = cliente.getRegistroConsumo();
			Vector<Consumo> consumos = registroConsumo.getConsumos();
			if (consumos.size() > 0){
				Factura factura = new Factura(cliente);
				float total = 0;
				for(Consumo consumo : consumos){						
						float valor = 0;
						Servicio servicio = consumo.getServicio();
						valor = consumo.getCantidadConsumida() * servicio.getPrecio();
						total += valor;
						ItemFactura itemFactura = new ItemFactura(servicio, valor);
						factura.agregarItemFactura(itemFactura);						
				}
				factura.setTotal(total);
				facturas.add(factura);
			}
		}
	}
	
	public Vector<ServicioView> getServiciosDisponibles(){
		Vector<ServicioView> serviciosView = new Vector<ServicioView>();
		for (Servicio serv : servicios){
			serviciosView.add(serv.getView());
		}
		return serviciosView;
	}
	
	public void altaPaquete (String descripcion, float descuento){
		Paquete nuevoPaquete = new Paquete(descuento, descripcion);
		servicios.add(nuevoPaquete);
	}
}
